# ImageColumn
require 'RMagick'
include Magick

module ImageColumn
  def self.included(base) # :nodoc:
    base.extend ClassMethods
  end
  class  ImageColumnString < String
    def self.append_attr attr
      attr.each do |a| attr_accessor a end
    end
    def initialize (path,ext,attr={ })
      super(path + "default"  + ext)
      attr.each_key do |a|
        self.send("#{a}=",path + a.to_s  + ext)
      end
    end

  end

  class DefaultFileNotFound < IOError
  end
  class AttributeNotSpecified < IOError
  end

  module ClassMethods
    PUBLIC_PATH=File.dirname(__FILE__) + "/../../../../public/images/"

    DEFAULT_OPTIONS={
      :path_to=>"",
      :ext=>".jpg",
      :attr=>:name,
      :crop=>{:default=>"300" }
    }.freeze

    def image_column(attr,options={ })
      options[:ext].insert(0,".") if options[:ext]
      options=DEFAULT_OPTIONS.merge(options)
      path = options[:path_to]
      ext = options[:ext]
      options[:crop].each_key do |k|
        unless File.exist?(PUBLIC_PATH +
                           path + k.to_s + ext)
          raise DefaultFileNotFound,
          "Default file is not found for image_column(#{ attr}.#{k.to_s}):" +
          PUBLIC_PATH + path + k.to_s + ext,caller
        end
      end

      unless self.column_names.include?(options[:attr].to_s)
        raise AttributeNotSpecified, "Attribute is not specified, which is used path to save images"
      end

      ImageColumnString.append_attr options[:crop].keys
      before_validation do |record|
        record[attr] = ImageColumnString.new(options[:path_to],
                                         ext,
                                         options[:crop]) if record[attr].nil?
      end
      validates_each attr do |record,attr,value|

        if value.respond_to?(:path)
          if !(value.content_type =~ /^image\/(jpg|jpeg|png|gif)/)
            record.errors.add attr, _(attr.to_s.humanize) +
              " content type error"
            next
          end
          file_path= options[:path_to] + "#{record[:name]}/"
          unless File.exists?(PUBLIC_PATH + file_path)
            Dir.mkdir(PUBLIC_PATH + file_path)
          end
          unless value.path.nil?
            orig = Image.read(value.path)[0]
          else
            orig = Image.from_blob(value.read)[0]
          end
          unless orig.format.downcase =~ /(jpg|jpeg|png|gif)/
            record.errors.add attr, _(attr.to_s.humanize) + " mime type error"
            next
          end

          rounded = Proc.new{ |base,angle|
            m = Image.new(base.columns,base.rows){
              self.background_color="transparent"}
            d = Draw.new
            d.roundrectangle(0,0,base.columns,base.rows,angle,angle)
            d.draw(m)
            r = m.composite(base,0,0,SrcInCompositeOp)
            r
          }
          crop = Proc.new{ |base, size, path|
            ret = base.crop_resized(size,size)
            ret = rounded.call(ret,options[:round]) if options[:round]
            ret.write(PUBLIC_PATH + path)
            ret
          }
          im = ImageColumnString.new(file_path,ext,options[:crop])
          record[attr] = im
          options[:crop].each do |ftype,size|
            crop.call orig,size.to_i,file_path + ftype.to_s + ext
          end

        elsif value.class==ImageColumnString
          next
        elsif !value.nil?
          record.errors.add attr, _(attr.to_s.humanize) + " class error"
        end
      end

      define_method(:after_find){
        if !img.nil? and File.exists?(PUBLIC_PATH + img)
          dir = File.dirname(img) + "/"
          e = File.extname(img)
          i = ImageColumnString.new(dir,e,options[:crop])
          write_attribute(:img,i)
        end
      }

      define_method(attr.to_s+"="){ |p|
        if p.class==String and p==""
          return
        end
        super(p)
        nil
      }

    end
  end
end
